/*
 * jeu.c
 * projet Unix: 6 qui prend
 *
 *  @authors Doublier Sami
 *  @authors Pingot Alexandre
 */

#include "jeu.h"

int semaphore_set_id = 0;
int shmID = 0; /*Identifiant de la mémoire partagée*/
int shmIDReset = 0;
int nbrJoueurs = 0;
int joueurs[MAX_JOUEURS];
int serveurSocket = 0;
int maxFdp = 0;
int cartes[TOTAL_CARTES]; /*cartes à repartir et à mélanger à chaque manche*/

choix carte_proposees[MAX_JOUEURS];

fd_set * ensemble_lecture;

/*Pointeur vers la mémoire partagée*/
sharedMem * shmAddr;
sharedCounter * shmCountAddr;

/*Pointeur vers la mémoire partagée destinée à l'écriture*/
sharedMem * memoireServeur;

int semaphore_key = 424242;
int shm_key = 654575;
int shmReset_key = 341426;
int lockfile = 0;

void partie(int socket, int lock) {
	message msg;

	struct itimerval old;
	static struct sigaction sig;
	struct sigaction sigInt;

	serveurSocket = socket;
	maxFdp = serveurSocket;
	lockfile = lock;

	/* initialisation de la structure sigaction pour gérer
	 *  le signal qui sera declenche après un ctrl+c */
	sigInt.sa_flags = 0;
	sigInt.sa_handler = signalIntHandler;

	/* On se met à l'ecoute du signal SIGINT */
	SYSS(sigaction(SIGINT, &sigInt, NULL));

	/* Permet de faire un reset du timer */
	old.it_interval.tv_sec = 0;
	old.it_interval.tv_usec = 0;
	old.it_value.tv_sec = 0;
	old.it_value.tv_usec = 0;

	sig.sa_flags = SA_RESTART;
	sigemptyset(&sig.sa_mask);
	sig.sa_handler = signalHandler;

	/* On se met à l'ecoute du signal SIGALRM emit par le timer */
	SYSS(sigaction(SIGALRM, &sig, NULL));
	/* L'initialisation ne se fait qu'une seule fois */
	fprintf(stderr, "\ninitialiserLesRessources Ligne 74\n");
	initialiserLesRessources();
	/* Un tour de boucle signifie une partie sur le serveur */

	while (1) {
		fprintf(stderr, "\nnettoyerLesRessources Ligne 79\n");
		nettoyerRessources();

		/* connexion de nouveaux clients */
		fprintf(stderr, "\naccepterJoueurs Ligne 84\n");
		accepterJoueurs();

		/* Le timer doit s'arrêter sinon il arrete les prochains select*/
		fprintf(stderr, "\nLancement d'un timer Ligne 89\n");
		SYSS(setitimer(ITIMER_REAL, &old, NULL));

		/* On ne continue pas si le nombre de joueurs minimum n'est pas atteint */

		/* On reinitialise toutes les ressources communes à chaque manche */
		msg.type = CLOSE;
		strcpy(msg.content, "Il n'y a pas assez de joueur");

		if (pasAssezDeJoueurs(&msg))
			continue;

		serveurSocket = socket;

		/* Initialisation du message d'accueil des joueurs */
		msg.type = BIENVENUE;
		strcpy(msg.content, "Bienvenue sur le serveur de jeu 6 qui prend");
		fprintf(stderr, "\n ecrireAuxJoueurs Ligne 114\n");
		ecrireAuxJoueurs(&msg);
		bzero(&msg, sizeof(message));

		/**************************************************************************/
		fprintf(stderr, "\n enregistrerNomsJoueurs Ligne 119\n");
		enregistrerNomsJoueurs();
		if (nbrJoueurs < MINPLAYERS)
			continue;
		fprintf(stderr, "initialiserLesCartes() Ligne 123\n");/*TODO pour les tests*/
		initialiserLesCartes();

		/* on sauve le nombre de joueurs dans la copie de la memoire partagée */
		memoireServeur->joueurs = nbrJoueurs;

		fprintf(stderr, "envoiDesResources() ligne 137\n");
		envoiDesResources();
		fprintf(stderr, "distribuerLesCartes() ligne 139\n");
		distribuerLesCartes();
		fprintf(stderr, "tourDeJeu() ligne 141\n");
		tourDeJeu();
	}
}

typedef int(*fncmp)(const void *, const void *);

int comp(choix *a, choix *b){
	return a->carte - b->carte;
}

void placerLesCartes() {
	int i = 0;
	int j = 0;
	message msg;
	int valeurCarteProposee;
	int positionPGLigne, positionPGLigne2;
	int valeurDeLaCarteLaPlusGrande;

	int meilleurePositionSurlaLgine = -1;
	int ancienneMeilleurePositionSurlaLgine = -1;
	qsort(carte_proposees,nbrJoueurs,sizeof(choix),((fncmp) comp));

	fprintf(stderr,"\n");
	for (i = 0; i < MAX_JOUEURS; i++) {/*On parcours le tableau de propositions de chaques joueurs*/
		meilleurePositionSurlaLgine = -1;
		ancienneMeilleurePositionSurlaLgine = -1;
		if (carte_proposees[i].carte != VIDE) {/*Vérifie que le joueur est bien présent*/
			valeurCarteProposee = carte_proposees[i].carte;
			fprintf(stderr,"ligne 172 valeurCarteProposee %d\n",valeurCarteProposee);
			for (j = 0; j < CARTES_LIGNE; j++) {/*On parcours les lignes*/
				positionPGLigne = memoireServeur->cartesSurLaTable[j][0];/*donne la position de la plus grande carte sur la ligne*/
				valeurDeLaCarteLaPlusGrande = memoireServeur->cartesSurLaTable[j][positionPGLigne];
				fprintf(stderr,"ligne 176 valeurDeLaCarteLaPlusGrande %d\n",valeurDeLaCarteLaPlusGrande);
				if (valeurDeLaCarteLaPlusGrande < valeurCarteProposee) {/*On récupère la position*/
					fprintf(stderr,"ligne 178 meilleurePositionSurlaLgine %d\t",meilleurePositionSurlaLgine);
					fprintf(stderr,"ligne 179 ancienneMeilleurePositionSurlaLgine %d\n",ancienneMeilleurePositionSurlaLgine);
					if (meilleurePositionSurlaLgine == -1) {/*si on n'a pas déjà une position */
						meilleurePositionSurlaLgine = j;/*on prend la position courante*/
					} else { /*Si on avait déjà une position*/
						ancienneMeilleurePositionSurlaLgine = meilleurePositionSurlaLgine;/*On met la nouvelle dans l'ancienne*/
						meilleurePositionSurlaLgine = j; /*Et on prend la position courante*/
					}
				}
				fprintf(stderr,"ligne 187 meilleurePositionSurlaLgine %d\t",meilleurePositionSurlaLgine);
				fprintf(stderr,"ligne 188 ancienneMeilleurePositionSurlaLgine %d\n",ancienneMeilleurePositionSurlaLgine);
				if (meilleurePositionSurlaLgine != -1 && ancienneMeilleurePositionSurlaLgine != -1) { /*Si on a 2 position possible*/
					fprintf(stderr,"ligne 190 \tmeilleurePositionSurlaLgine %d\tancienneMeilleurePositionSurlaLgine %d\tpositionPGLigne %d\tpositionPGLigne2 %d\n",meilleurePositionSurlaLgine,ancienneMeilleurePositionSurlaLgine,positionPGLigne,positionPGLigne2);

					positionPGLigne = memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0];
					positionPGLigne2 = memoireServeur->cartesSurLaTable[ancienneMeilleurePositionSurlaLgine][0];
					fprintf(stderr,"ligne 194 abs( valeurCarteProposee  - memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne]) %d\n",abs( valeurCarteProposee  - memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne]));
					fprintf(stderr,"ligne 195 abs( valeurCarteProposee - memoireServeur->cartesSurLaTable[ancienneMeilleurePositionSurlaLgine][positionPGLigne2]) %d\n",abs( valeurCarteProposee - memoireServeur->cartesSurLaTable[ancienneMeilleurePositionSurlaLgine][positionPGLigne2]));
					if (abs( valeurCarteProposee  - memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne])
							> abs( valeurCarteProposee - memoireServeur->cartesSurLaTable[ancienneMeilleurePositionSurlaLgine][positionPGLigne2])) {

						meilleurePositionSurlaLgine = ancienneMeilleurePositionSurlaLgine;
					}
				}
			}/* Sortie du for de parcours des cartes sur la table */


			fprintf(stderr,"\n\n\nPassage à la suite\n\n\n");
			/* Test si une position a été trouvée */
			if (meilleurePositionSurlaLgine == -1) {
				int readBytes;
				fprintf(stderr,"\t ligne 179 Si la carte proposée est trop petite :\n");
				bzero(&msg, sizeof(message));
				msg.type = CHOIX_RANGEE;
				sprintf(msg.content,"Ta carte est trop petite, tu dois manger, alors choisi une rangée:");
				SYS(write(joueurs[carte_proposees[i].numero_joueur], &msg, sizeof(message)));

				fprintf(stderr, "Lis l'emplacement de la carte proposé par le joueur ligne 185\n");
				bzero(&msg, sizeof(message)); /* Initialise le message à 0 */
				SYSS(readBytes = read(meilleurePositionSurlaLgine, &msg, sizeof(message)));
				if (readBytes != 0) {
					if (msg.type == CHOIX_RANGEE) {
						memoireServeur->totaux_points[carte_proposees[i].numero_joueur]= memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0];
						memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0]= 0;
						for (i = 1; i < CARTES_LIGNE; i++) {
							memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][i] = VIDE;
						}
					}
				} else if (readBytes == 0) {
					fprintf(stderr, "Le joueur ne propose rien => déconnecté ligne 197 \n");
					bzero(&msg, sizeof(message)); /* préparation de l'envoie d'un message d'erreur */
					msg.type = CLOSE;
					strcpy(msg.content,"Vous avez été déconnecté: Pas de réponse de votre part !");
					closeConnectionClient( joueurs[carte_proposees[i].numero_joueur], &msg);

					bzero(&msg, sizeof(message));
					msg.type = MESSAGE;
					if (strcmp("Joueur", memoireServeur->nom[carte_proposees[i].numero_joueur])== 0) {
						sprintf( msg.content, "%s %d a quitté la partie", memoireServeur->nom[carte_proposees[i].numero_joueur], joueurs[carte_proposees[i].numero_joueur]);
					} else {
						sprintf( msg.content, "%s a quitté la partie", memoireServeur->nom[carte_proposees[i].numero_joueur]);
					}

					nbrJoueurs--;
					FD_CLR(joueurs[carte_proposees[i].numero_joueur], ensemble_lecture);
				}
			} else {
				fprintf( stderr, "\tligne 228 La carte proposée n'est pas trop petite => vérification que ce n'est pas la dernière\n");
				if (memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0] == 5) {
					fprintf(stderr, "\tc'est la derniere ligne 230\n");
					memoireServeur->totaux_points[carte_proposees[i].numero_joueur] = memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0];
					memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0] = 0;
					for (i = 1; i < CARTES_LIGNE; i++) {
						memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][i] = VIDE;
					}
				}
			}

			fprintf(stderr, "\tTout est enfin ok on place la carte 265\n");

			memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0] += 1;
			positionPGLigne2 = memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][0];

			fprintf( stderr, "\tmeilleurePositionSurlaLgine : %d\tpositionPGLigne2 : %d\n", meilleurePositionSurlaLgine, positionPGLigne2);
			fprintf( stderr, "\tmemoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne2]: %d \n", memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne2]);

			memoireServeur->cartesSurLaTable[meilleurePositionSurlaLgine][positionPGLigne2] = carte_proposees[i].carte;

		}/* Sortie du if de test si carte vide ou pas*/
	}/* Sortie du for qui parcours toutes les propositions */
	fprintf(stderr, "redacteur() ligne 238\n");
	redacteur(memoireServeur, shmAddr, semaphore_set_id);
	for (i = 0; i < MAX_JOUEURS; i++) {
		carte_proposees[i].carte = VIDE;
		carte_proposees[i].numero_joueur = VIDE;
	}
}

/* Cette fonction permet de ne laisser aucun ipc sur le système et
 * de fermer le serveur proprement */
void signalIntHandler(int signal) {
	int a;
	message msg, msgRc;
	msg.type = CLOSE;
	strcpy(msg.content, "Le serveur est éteind!");
	fprintf(stderr, "SIGINT : %d\n", signal);

	for (a = 0; a < MAX_JOUEURS; a++) {

		if (joueurs[a] != 0) {
			SYS(write(joueurs[a], &msg, sizeof(message)));
			SYS(read(joueurs[a], &msgRc, sizeof(message)));
			SYS(close(joueurs[a]));
		}
	}

	if (lockfile != 0) {
		SYS(unlink(LOCK));
	}

	if (semaphore_set_id != 0) {
		SYS(semctl(semaphore_set_id, 0, IPC_RMID));
	}

	if (shmID != 0) {
		SYS(shmdt(shmAddr));
		SYS(shmctl(shmID, IPC_RMID, NULL));
	}

	if (shmIDReset != 0) {
		SYS(shmdt(shmCountAddr));
		SYS(shmctl(shmIDReset, IPC_RMID, NULL));
	}

	if (serveurSocket != 0) {
		SYS(close(serveurSocket));
	}
	exit(3);
}

void tourDeJeu() {
	int tour; /* compteur de tour cyclique, revient à zero à la fin d'un tour de table des joueurs */
	/* Au fur et à mesure d'une partie, les deconnexions peuvent survenir
	 il faut donc prendre dans le tableau des joueurs le nième socket,
	 nième correspondant à la valeur de tour  */
	int numJoueurTableau;
	int j;
	int k;
	int cptNombreDePropositions = 0;
	tour = 0;
	k = 0;

	while (1) {

		int suivant;
		/* Si le descripteur en cours existe on traite la lecture
		 * et que le descripteur est different de mySocket */
		int event;
		int readBytes;
		struct sockaddr_in client;
		int clientSocket;
		fd_set rfds;
		message msg;
		socklen_t adr_len_cli;
		suivant = 1;
		bzero(&msg, sizeof(message));
		msg.type = GAGNANT_PAR_DEFAUT;
		sprintf(msg.content, "Tu as gagné par défaut");
		if (pasAssezDeJoueurs(&msg)) {
			return;
		}

		/* Il faut determiner à qui est le tour */
		numJoueurTableau = 0;
		j = 0;
		for (numJoueurTableau = 0; numJoueurTableau < MAX_JOUEURS; numJoueurTableau++) {
			if (joueurs[numJoueurTableau] != 0 && j++ == tour)
				break;
		}

		bzero(&msg, sizeof(message));
		msg.type = CARTE;

		if (strcmp("Joueur", memoireServeur->nom[event]) == 0) {
			sprintf(msg.content, "%s %d, c'est ton tour.",
					memoireServeur->nom[numJoueurTableau + 1],
					numJoueurTableau + 1);
		} else {
			sprintf(msg.content, "%s, c'est ton tour.",
					memoireServeur->nom[numJoueurTableau + 1]);
		}
		SYSS(write(joueurs[numJoueurTableau], &msg, sizeof(message)));

		while (suivant) {
			bzero(&msg, sizeof(message));
			msg.type = GAGNANT_PAR_DEFAUT; /* Dans l'éventualité ou les autres joueurs se sont déconnectés */
			sprintf(msg.content,
					"Tu as gagné : les autres joueurs se sont déconnectés.");
			if (pasAssezDeJoueurs(&msg)) {
				return;
			}

			/**
			 * Utilisation d'un select pour savoir si un joueur est arrivé:
			 * -> le select = -1 et errno = EINTR => ALARM
			 * -> le select = -1 et errno != EINTR => Sortie du jeu
			 * */
			FD_ZERO(&rfds); /* met la structure du select à 0 */
			memcpy(&rfds, ensemble_lecture, sizeof(rfds));

			SYSS(select(maxFdp + 1, &rfds, 0, 0, NULL)); /* maxFdp -> socket du client qui se connecte */

			/* Dans le cas ou une partie est déjà en cours */
			if (FD_ISSET(serveurSocket, &rfds)) {
				SYSS(clientSocket = accept(serveurSocket,(struct sockaddr *) &client, &adr_len_cli)); /* Accepte le client qui se connecte au socket du serveur */

				/* On vide le buffer quand un client se connecte */
				SYSS(fflush(stdout));

				bzero(&msg, sizeof(message));
				msg.type = CLOSE; /* Envoi un message de type fermeture car la partie est déjà commencée */
				strcpy(msg.content, "La partie a dejà commencée");
				SYSS(write(clientSocket, &msg, sizeof(message)));
				SYSS(close(clientSocket));
			} else {
				/* On regarde quel joueur a proposé une carte */
				for (event = 0; event < MAX_JOUEURS; event++) {
					if (joueurs[event] != 0) {
						/* Le serveur analyse la carte reçue par un joueur */
						if (FD_ISSET(joueurs[event], &rfds)) { /* si le client propose une carte */
							bzero(&msg, sizeof(message)); /* Initialise le message à 0 */
							SYSS(readBytes = read(joueurs[event], &msg, sizeof(message))); /* On lit la carte envoyée par le joueur  */
							if (readBytes != 0 && event == numJoueurTableau) { /* On vérifie que l'on a réellement reçus qque chose et que c'est le tour du bon joueur */
								if (msg.type == CARTE) {/* On regarde le type du msg envoyé par le client */
									int numCarte;
									numCarte = atoi(msg.content); /* Récupération de la valeur de la carte */

									if (numCarte == 0) { /* Si la valeur retournée par le atoi == 0 car pas un nombre */
										bzero(&msg, sizeof(message)); /* préparation de l'envoie d'un message d'erreur */
										msg.type = CLOSE;
										strcpy(msg.content,
												"Vous avez été déconnecté: Pas de réponse de votre part !");
										closeConnectionClient(joueurs[event],
												&msg);

										bzero(&msg, sizeof(message));
										msg.type = MESSAGE;
										if (strcmp("Joueur",
												memoireServeur->nom[event])
												== 0) {
											sprintf(msg.content,
													"%s %d a quitté la partie",
													memoireServeur->nom[event],
													joueurs[event]);
										} else {
											sprintf(msg.content,
													"%s a quitté la partie",
													memoireServeur->nom[event]);
										}
										ecrireAuxJoueursSauf(&msg,
												joueurs[event]);
										suivant = 0;
										tour = (tour + 1) % nbrJoueurs; /* on passe au joueur suivant */
									}
									/*##################################################################*/


									for (j = 0; j < MAX_CARTES_PAR_JOUEUR; j++) { /*Initialisation du tableau de proposition*/

										fprintf(stderr,"\t\tevent %d ligne 582\n",event);
										if (memoireServeur->visible[event][j] == numCarte) {
											memoireServeur->visible[event][j] = VIDE;
											carte_proposees[cptNombreDePropositions].carte = numCarte;
											carte_proposees[cptNombreDePropositions].numero_joueur = event;

											cptNombreDePropositions++;
											break;
										}
									}
									fprintf(stderr,"\t\tEvent %d\n",event);
									if (cptNombreDePropositions == nbrJoueurs) {
										fprintf(stderr,"placerLesCartes() ligne 639\n");

										placerLesCartes();
										cptNombreDePropositions = 0;

										/* manche terminée */
										if (j == MAX_CARTES_PAR_JOUEUR - 1) {

											bzero(&msg, sizeof(message));
											msg.type = CLOSE;
											sprintf(msg.content,
													"La manche est terminée !");
											ecrireAuxJoueurs(&msg);

											/* demande d'affichage des points */
											bzero(&msg, sizeof(message));
											msg.type = AFFICHER_POINTS;
											ecrireAuxJoueurs(&msg);

											return;

										}
										/* gagnant de partie */
										if (memoireServeur->totaux_points[event]
												== POINT_POUR_TERMINER_PARTIE) {

											bzero(&msg, sizeof(message));
											msg.type = GAGNANT_PARTIE;
											sprintf(msg.content,
													" Bravo, tu as gagné la partie !");
											SYS(write(joueurs[event], &msg, sizeof(message)));
											bzero(&msg, sizeof(message));

											msg.type = MESSAGE;

											if (strcmp("Joueur",
													memoireServeur->nom[event])
													== 0) {
												sprintf(
														msg.content,
														"La partie est remportée par %s %d",
														memoireServeur->nom[event],
														joueurs[event]);
											} else {
												sprintf(
														msg.content,
														"La partie est remportée par %s",
														memoireServeur->nom[event]);
											}
											ecrireAuxJoueursSauf(&msg,
													joueurs[event]);

											bzero(&msg, sizeof(message));
											msg.type = CLOSE;
											sprintf(msg.content,
													"La partie est terminée !");
											ecrireAuxJoueurs(&msg);

											/* demande d'affichage des points */
											bzero(&msg, sizeof(message));
											msg.type = AFFICHER_POINTS;
											ecrireAuxJoueurs(&msg);

											return;

										}

										redacteur(memoireServeur, shmAddr,
												semaphore_set_id);
										suivant = 0;
									}else {
										tour = (tour + 1) % nbrJoueurs; /* on passe au joueur suivant */
										suivant = 0;
										break;
									}

								}
							} else if (readBytes == 0) {

								bzero(&msg, sizeof(message)); /* préparation de l'envoie d'un message d'erreur */
								msg.type = CLOSE;
								strcpy(msg.content,
										"Vous avez été déconnecté: Pas de réponse de votre part !");
								closeConnectionClient(joueurs[event], &msg);

								bzero(&msg, sizeof(message));
								msg.type = MESSAGE;
								if (strcmp("Joueur", memoireServeur->nom[event])
										== 0) {
									sprintf(msg.content,
											"%s %d a quitté la partie",
											memoireServeur->nom[event],
											joueurs[event]);
								} else {
									sprintf(msg.content,
											"%s a quitté la partie",
											memoireServeur->nom[event]);
								}

								nbrJoueurs--;
								FD_CLR(joueurs[event], ensemble_lecture);

								/* Lorsqu'on est en attente du dernier joueur et que celui ci se deconnecte,
								 * il faut demander un carte au premier joueur à la prochaine iteration de la boucle.
								 * Si c'est un joueur autre que celui attendu, le serveur continue d'attendre */
								if (numJoueurTableau == event) {
									suivant = 0;/* On passe au suivant */
									tour = tour % nbrJoueurs;
								} else if (tour != 0) {
									tour--;
								}

								joueurs[event] = 0;
								maxFd();/* La variable maxFdp doit changer après avoir supprimé un joueur */
								memoireServeur->joueurs = nbrJoueurs;
								/* On écrit le changement du nombre de joueurs
								 *  dans la memoire partagee */

								redacteur(memoireServeur, shmAddr,
										semaphore_set_id);
								ecrireAuxJoueurs(&msg);
							}
						}
					}/* fermeture du if qui test si joueurs[event] est différent de 0*/
				}/* fermeture du for qui parcours la liste des joueurs */
			}/* fermeture du else qui vérifie que la partie n'est pas déjà en cours */
		}/* fermeture while(suivant)*/
	}
}

/* Cette fonction comme son nom l'indique accepte les joueurs dans les limites
 * autorisees du jeu c'est à dire 1 minute après la connexion du premier
 * client et n'accepte que 10 joueurs maximum */
void accepterJoueurs() {

	struct itimerval timer;
	struct itimerval old;
	/* Timer client */
	timer.it_interval.tv_sec = 0;
	timer.it_interval.tv_usec = 0;
	timer.it_value.tv_sec = CONNEXION_TIMEOUT;
	timer.it_value.tv_usec = 0;

	/* Permet de faire un reset du timer */
	old.it_interval.tv_sec = 0;
	old.it_interval.tv_usec = 0;
	old.it_value.tv_sec = 0;
	old.it_value.tv_usec = 0;

	while (1) {
		int event;
		int selectTest;
		int clientSocket;
		struct sockaddr_in client;
		fd_set rfds;
		socklen_t adr_len_cli = sizeof(client);
		/* copie des listes de sockets de ensemble_lecture vers rfds*/

		FD_ZERO(&rfds);

		memcpy(&rfds, ensemble_lecture, sizeof(rfds));
		/* si selectTest est egal à -1 et errno == EINTR l'alarme a sonne,
		 * si la valeur de selectTest est egal à -1 et errno != EINTR on sort du jeu */
		if ((selectTest = select(maxFdp + 1, &rfds, 0, 0, NULL)) == -1) {
			if (errno == EINTR) {
				/* Le timeout est fini pour l'acceptation des joueurs */
				break;
			}
			fprintf(stderr, "kill(getPid(),SIGINT) Ligne 624\n");
			kill(getpid(), SIGINT);
		}

		/* verification de l'arrivee d'evenements sur le socket mySocket */
		if (FD_ISSET(serveurSocket, &rfds)) {
			SYSS(clientSocket = accept(serveurSocket, (struct sockaddr *) &client,
							&adr_len_cli));
			/* On vide le buffer dès qu'un client arrive */
			SYSS(fflush(stdout));

			/* Acceptation des clients tant que nbrJoueurs < MAXPLAYERS */
			if (nbrJoueurs < MAX_JOUEURS) {
				FD_SET(clientSocket, ensemble_lecture);
				if (clientSocket > maxFdp)
					maxFdp = clientSocket;
				joueurs[nbrJoueurs++] = clientSocket;
				memoireServeur->joueurs++;
				if (nbrJoueurs == 1) {
					SYSS(setitimer(ITIMER_REAL, &timer, NULL));
				}
			}
		}

		else {
			/* On regarde où s'est passe l'evenement */
			for (event = 0; event < MAX_JOUEURS; event++) {
				if (joueurs[event] != 0) {
					/* Le serveur analyse le nom reçu par un joueur */
					if (FD_ISSET(joueurs[event], &rfds)) {
						int readBytes;
						message msg;
						bzero(&msg, sizeof(message));
						SYSS(readBytes=read(joueurs[event], &msg, sizeof(message)));
						if (readBytes == 0) { /* on a lu qqchose du serveur */
							int j;
							SYSS(close(joueurs[event]));
							FD_CLR(joueurs[event], ensemble_lecture);
							for (j = event; j < nbrJoueurs - 1; j++) {
								joueurs[j] = joueurs[j + 1];
							}

							joueurs[j] = 0;
							nbrJoueurs--;
							maxFd();/* La variable maxFdp doit changer après avoir supprime un joueur */
							bzero(&msg, sizeof(message));
							msg.type = MESSAGE;
							if (strcmp("Joueur", memoireServeur->nom[event])
									== 0) {
								sprintf(msg.content,
										"%s %d a quitté la partie",
										memoireServeur->nom[event], event + 1);
							} else {
								sprintf(msg.content, "%s s'est deconnecté.",
										memoireServeur->nom[event]);
							}
							fprintf(stderr, "ecrireAuxJoueurs() Ligne 675\n");
							ecrireAuxJoueurs(&msg);
						}
					}
				}
			}
		}
		if (nbrJoueurs == MAX_JOUEURS)
			break;
		if (nbrJoueurs == VIDE) {
			SYSS(setitimer(ITIMER_REAL, &old, NULL));
		}
	}
}

void enregistrerNomsJoueurs() {
	int i;
	message msg;
	fd_set rfds;
	msg.type = NOM;

	strcpy(msg.content, "Introduisez votre nom:");
	fprintf(stderr, "ecrireAuxJoueurs() Ligne 698\n");
	ecrireAuxJoueurs(&msg);

	i = 0;

	while (i != nbrJoueurs) {
		/* Si le descripteur en cours existe on traite la lecture
		 * et que le descripteur est different de mySocket */
		int event;
		int readBytes;
		struct sockaddr_in client;
		int clientSocket;
		socklen_t adr_len_cli = sizeof(client);
		FD_ZERO(&rfds);
		memcpy(&rfds, ensemble_lecture, sizeof(rfds));

		fprintf(stderr, "\n\n\tnbrJoueurs %d Ligne 711\n\n", nbrJoueurs);
		/* si selectTest est egal à -1 et errno == EINTR l'alarme a sonne,
		 * si la valeur de selectTest est egal à -1 et errno != EINTR on sort du jeu */
		SYSS(select(FD_SETSIZE, &rfds, 0, 0, NULL));

		/* le client doit se terminer , on ne peut l'accepter pour jouer */
		if (FD_ISSET(serveurSocket, &rfds)) {
			SYSS(clientSocket = accept(serveurSocket, (struct sockaddr *) &client,&adr_len_cli));
			/* On vide le buffer quand un client arrive */
			SYSS(fflush(stdout));

			bzero(&msg, sizeof(message));
			msg.type = CLOSE;
			strcpy(msg.content, "Une partie est déjà en cours!");
			SYSS(write(clientSocket, &msg, sizeof(message)));
			SYSS(close(clientSocket));
		}

		else {
			/* On regarde où s'est passé l'evenement */
			for (event = 0; event < MAX_JOUEURS; event++) {
				if (joueurs[event] != 0) {
					/* Le serveur lit le nom reçu par un joueur */
					if (FD_ISSET(joueurs[event], &rfds)) {
						bzero(&msg, sizeof(message));
						SYSS(readBytes=read(joueurs[event], &msg, sizeof(message)));
						if (readBytes != 0) { /* on a lu quelque chose d'un client */
							switch (msg.type) {
							case NOM:
								strcpy(memoireServeur->nom[event], msg.content);
								i++;
								break;

							default:
								break;
							}
						} else if (readBytes == 0) {
							int j;
							close(joueurs[event]);
							FD_CLR(joueurs[event], ensemble_lecture);
							for (j = event; j < nbrJoueurs - 1; j++) {
								joueurs[j] = joueurs[j + 1];
							}
							joueurs[j] = 0;
							nbrJoueurs--;
							maxFd();/* La variable maxFdp doit changer après avoir supprime un joueur */
							bzero(&msg, sizeof(message));

							msg.type = CLOSE;
							strcpy(msg.content,
									"Trop de joueurs se sont deconnectés avant le début de la partie.");

							if (pasAssezDeJoueurs(&msg))
								return;
							bzero(&msg, sizeof(message));
							msg.type = MESSAGE;
							if (strcmp("Joueur", memoireServeur->nom[event])
									== 0) {
								sprintf(msg.content, "%s %d s'est deconnecté.",
										memoireServeur->nom[event],
										joueurs[event]);
							} else {
								sprintf(msg.content, "%s s'est deconnecté.",
										memoireServeur->nom[event]);
							}
							fprintf(stderr, "ecrireAuxJoueur() Ligne 778\n");
							ecrireAuxJoueurs(&msg);
						}
					}
				}
			}
		}
	}
}

void initialiserLesRessources() {
	/* initialiser les ressources */
	int fd;
	int i;
	fd = 0;
	semaphore_set_id = semInit(semaphore_key, 1);

	shmID = shmInit(shm_key, sizeof(struct sharedMem));
	shmIDReset = shmInit(shmReset_key, sizeof(struct sharedCounter));

	/*le pointeur vers notre memoire */
	shmAddr = (sharedMem *) shmAttach(shmID, (char*) shmAddr);
	shmCountAddr = (sharedCounter *) shmAttach(shmIDReset,
			(char *) shmCountAddr);

	SYSM(ensemble_lecture = (fd_set *) malloc(sizeof(fd_set)));
	SYSM(memoireServeur = (sharedMem*) malloc(sizeof(sharedMem)));

	/* Initialisation des cartes */
	for (i = 1; i <= TOTAL_CARTES; i++) {
		cartes[i - 1] = i;
	}

	for (i = 0; i < MAX_JOUEURS; i++) {
		carte_proposees[i].carte = VIDE;
		carte_proposees[i].numero_joueur = VIDE;
	}
}

void nettoyerRessources() {
	int fd;
	int i, j;
	/* on nettoie toutes les structures et variables sauf la table de repartition */

	memoireServeur->joueurs = 0;

	bzero(memoireServeur->visible, MAX_CARTES_PAR_JOUEUR * sizeof(int));
	for (fd = 0; fd < MAX_JOUEURS; fd++) {
		bzero(memoireServeur->nom[fd], LONG_NOM * sizeof(char));
		bzero(memoireServeur->visible[fd], MAX_CARTES_PAR_JOUEUR * sizeof(int));
	}
	for (i = 0; i < CARTES_LIGNE; i++) {
		for (j = 0; j < CARTES_COLONNE; j++) {
			memoireServeur->cartesSurLaTable[i][j] = VIDE;
		}
	}
	fprintf(stderr, "redacteur() ligne 835\n");
	redacteur(memoireServeur, shmAddr, semaphore_set_id);

	nbrJoueurs = 0;
	/** remise à zero de toutes les structures */
	FD_ZERO(ensemble_lecture);

	/* Ajout du socket serveur*/
	FD_SET(serveurSocket, ensemble_lecture);

	/** Initialisation du tableau qui contiendra les sockets client */
	for (fd = 0; fd < MAX_JOUEURS; fd++) {
		joueurs[fd] = 0;
	}
}

/* Doit être appellé à chaque debut de partie après la methode initialiserLesRessources*/
void initialiserLesCartes() {
	int i, j, k;
	int cpt;

	k = 0;
	/* initialise le tableau des cartes des joueurs */

	/* appel de la methode pour melanger ce tableau */
	fprintf(stderr, "melange() ligne 868\n");
	melange(cartes, sizeof(cartes) / sizeof(int));


	/* distribution des cartes entre les differents joueurs*/
	cpt = 0;
	for (i = 0; i < nbrJoueurs; i++) {
		for (j = 0; j < MAX_CARTES_PAR_JOUEUR; j++) {
			memoireServeur->visible[i][j] = cartes[cpt];
			cpt++;
		}
	}

	/* Ecriture des cartes visibles sur la table */
	for (i = 0; i < CARTES_LIGNE; i++) {
		memoireServeur->cartesSurLaTable[i][0] = 1;/* On met à l'indice zero qu'il y a une carte au début de chaque rangée*/
		memoireServeur->cartesSurLaTable[i][1] = cartes[cpt++]; /*place les cartes en colonne 1*/
	}

}

void melange(int * tab, size_t taille) {
	int i, carte;

	srand(time(NULL));

	for (i = 0; i < (int) taille; i++) {
		int rand_index = rand() % (TOTAL_CARTES);
		carte = tab[i];
		tab[i] = tab[rand_index];
		tab[rand_index] = carte;
	}
}

int pasAssezDeJoueurs(message * msg) {
	if (nbrJoueurs == GAGNANT_PAR_DEFAUT) {
		fprintf(stderr, "ecrireAuxJoueurs() ligne 915\n");
		ecrireAuxJoueurs(msg);
		return 1;
	}

	if (nbrJoueurs == VIDE) {
		return 1;
	}
	return 0;
}

void envoiDesResources(void) {
	message msg;
	/* partage des resources */
	/** envoi de la cle du semaphore */
	bzero(&msg, sizeof(message));
	msg.type = SEMAPHORE_SET_ID;
	sprintf(msg.content, "%d", semaphore_set_id);
	fprintf(stderr, "ecrireAuxJoueurs() ligne 933\n");
	ecrireAuxJoueurs(&msg);

	/** envoi de la cle de la memoire partagee */
	bzero(&msg, sizeof(message));
	msg.type = SHARED_MEM;
	sprintf(msg.content, "%d", shmID);
	fprintf(stderr, "ecrireAuxJoueurs() ligne 941\n");
	ecrireAuxJoueurs(&msg);

	/* envoi de la cle de la memoire partagee de
	 * l'indice compteur de processus lecteur */
	bzero(&msg, sizeof(message));
	msg.type = SHARED_MEM_RC;
	sprintf(msg.content, "%d", shmIDReset);
	fprintf(stderr, "ecrireAuxJoueurs() ligne 948\n");
	ecrireAuxJoueurs(&msg);
}

void distribuerLesCartes() { /*TODO Cette méthode n'envoie plus que le numéro du joueur et demande au client d'attacher la mémoire partagée*/
	int fds;
	message messg;
	char buffer[MAXLINE];

	fprintf(stderr, "Ligne 967 \tNUMERO :\t%d\n", NUMERO);

	for (fds = 0; fds < MAX_JOUEURS; fds++) {
		if (joueurs[fds] != 0) {


			bzero(buffer, MAXLINE * sizeof(char));
			bzero(&messg, sizeof(message));
			messg.type = NUMERO;
			bzero(messg.content, MAXLINE * sizeof(char));
			sprintf(messg.content, "%d", fds);
			SYSS(write(joueurs[fds], &messg, sizeof(message)));

			bzero(&messg, sizeof(message));
			messg.type = CARTES_RECUES;
			bzero(messg.content, MAXLINE * sizeof(char));
			strcpy(messg.content, buffer);
			SYSS(write(joueurs[fds], &messg, sizeof(message)));
			fprintf(stderr, "\nLigne 1002 :\t%d\t%s\n", messg.type,
					messg.content);
		}
	}
}

void ecrireAuxJoueurs(message * messg) {
	int fds;
	for (fds = 0; fds < MAX_JOUEURS; fds++) {
		if (joueurs[fds] != 0) {
			SYSS(write(joueurs[fds], messg, sizeof(message)));
		}
	}
}

void ecrireAuxJoueursSauf(message * messg, int socket) {
	int fds;
	for (fds = 0; fds < MAX_JOUEURS; fds++) {
		if (joueurs[fds] != 0 && joueurs[fds] != socket) {
			SYSS(write(joueurs[fds], messg, sizeof(message)));
		}
	}
}

void maxFd() {
	int i;
	maxFdp = serveurSocket;
	for (i = 0; i < MAX_JOUEURS; i++) {
		if (joueurs[i] > maxFdp)
			maxFdp = joueurs[i];
	}
}

void signalHandler(int signal) {
	if (signal == SIGALRM)
		fprintf(stderr, "Temps ecoulé!\n");
}
